package com.yiwei.zhh.util;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.support.annotation.ColorRes;
import android.support.v4.app.Fragment;
import android.text.Html;
import android.text.Layout;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextPaint;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.AlignmentSpan;
import android.text.style.BackgroundColorSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.ImageSpan;
import android.text.style.LeadingMarginSpan;
import android.text.style.ReplacementSpan;
import android.text.style.StyleSpan;
import android.text.style.TypefaceSpan;
import android.text.style.UnderlineSpan;
import android.util.Log;
import android.view.View;

import java.util.ArrayList;
import java.util.List;

public class Spans { //
    public static Spanned fromHtml(Resources resources, int strId, Object... values) {
        synchronized (_ig) {
            _ig.resources = resources;
            return Html.fromHtml(resources.getString(strId, values), _ig, null);
        }
    }

    public static Spanned fromHtml(Context context, int strId, Object... values) {
        return fromHtml(context.getResources(), strId, values);
    }

    public static Builder with(Context context) {
        return new Builder(context);
    }

    public static Builder with(Fragment fragment) {
        return new Builder(fragment.getContext());
    }

    public static Builder with(View view) {
        return new Builder(view.getContext());
    }

    private static final ImageGetter _ig = new ImageGetter();

    private static class ImageGetter implements Html.ImageGetter {

        Resources resources;

        public Drawable getDrawable(String source) {
            Drawable d = null;
            try {
                d = resources.getDrawable(Integer.parseInt(source));
                d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
            } catch (Resources.NotFoundException e) {
                Log.e("ezy", "Image not found. Check the ID.", e);
            } catch (NumberFormatException e) {
                Log.e("ezy", "Source string not a valid resource ID.", e);
            }
            return d;
        }
    }

    /**
     * p : align, indent
     * img
     * font : size, color, style, background, typeface, rounded
     * <p>
     * new Span.Builder()
     * .p().align(Layout.Alignment.ALIGN_CENTER)
     * .font("\ue902").size(40, true).typeface(tf)
     * .p().align(Layout.Alignment.ALIGN_CENTER)
     * .font("Home").color(0xff262626).style(Typeface.BOLD).size(20, true)
     * .build()
     */
    public static class Builder {
        private SpannableStringBuilder mBuilder = new SpannableStringBuilder();
        private List<Object> mSpans = new ArrayList<>();
        private Context mContext;
        private int mCharacter;
        private int mParagraph;

        Builder(Context context) {
            mContext = context;
        }

        private void _s(Object span) {
            mBuilder.setSpan(span, mCharacter, mBuilder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
        }

        private void _p(Object span) {
            if (mParagraph < mBuilder.length()) {
                mBuilder.setSpan(span, mParagraph, mBuilder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }

        private void end() {
            for (Object span : mSpans) {
                _p(span);
            }
            mSpans.clear();
        }

        public Spanned build() {
            end();
            return mBuilder;
        }


        /**
         * p : align, indent
         */
        public Builder p() {
            end();
            if (mBuilder.length() > 0) {
                mBuilder.append("\n");
            }
            mParagraph = mBuilder.length();
            return this;
        }

        public Builder p(Layout.Alignment align, int indent) {
            return p().align(align).indent(indent);
        }

        public Builder align(Layout.Alignment align) {
            mSpans.add(new AlignmentSpan.Standard(align));
            return this;
        }

        public Builder indent(int first, int rest) {
            mSpans.add(new LeadingMarginSpan.Standard(first, rest));
            return this;
        }

        public Builder indent(int every) {
            mSpans.add(new LeadingMarginSpan.Standard(every));
            return this;
        }


        public Builder img(Drawable drawable) {
            return img(drawable, ImageSpan.ALIGN_BASELINE);
        }

        public Builder img(Drawable drawable, int verticalAlignment) {
            if (drawable.getBounds().isEmpty()) {
                drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
            }
            mCharacter = mBuilder.length();
            mBuilder.append(" ");
            _s(new ImageSpan(drawable, verticalAlignment));
            return this;
        }

        /**
         * font : style, color, size, background, typeface
         */
        public Builder font(String text) {
            mCharacter = mBuilder.length();
            mBuilder.append(text);
            return this;
        }

        public Builder font(String text, float size) {
            return font(text).size(size);
        }

        public Builder font(String text, float size, int color) {
            return font(text).size(size).color(color);
        }

        public Builder style(int style) {
            _s(new StyleSpan(style));
            return this;
        }

        public Builder colorResId(@ColorRes int res) {
            _s(new ForegroundColorSpan(mContext.getResources().getColor(res)));
            return this;
        }

        public Builder color(int color) {
            _s(new ForegroundColorSpan(color));
            return this;
        }

        public Builder underline() {
            _s(new UnderlineSpan());
            return this;
        }

        public Builder size(float size) {
            _s(new AbsoluteSizeSpan((int) size));
            return this;
        }

        public Builder size(float size, boolean px) {
            size = px ? size : Device.sp2px(size);
            _s(new AbsoluteSizeSpan((int) size));
            return this;
        }

        public Builder background(int color) {
            _s(new BackgroundColorSpan(color));
            return this;
        }

        public Builder typeface(Typeface typeface) {
            _s(new CustomTypefaceSpan("", typeface));
            return this;
        }

        public Builder rounded(float round, int backgroundColor) {
            _s(new RoundedBackgroundSpan(round, backgroundColor));
            return this;
        }
    }

    public static class RoundedBackgroundSpan extends ReplacementSpan {
        private float mRound = 0;
        private int mBackgroundColor = 0;

        public RoundedBackgroundSpan(float round, int backgroundColor) {
            mRound = round;
            mBackgroundColor = backgroundColor;

        }

        @Override
        public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
            return Math.round(paint.measureText(text, start, end));
        }


        @Override
        public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
            int color = paint.getColor();
            RectF rect = new RectF(x, 0, x + Math.round(paint.measureText(text, start, end)), bottom);
            paint.setColor(mBackgroundColor);
            canvas.drawRoundRect(rect, mRound, mRound, paint);
            paint.setColor(color);
            canvas.drawText(text, start, end, x, y, paint);
        }
    }

    public static class CustomTypefaceSpan extends TypefaceSpan {
        private final Typeface newType;

        public CustomTypefaceSpan(String family, Typeface type) {
            super(family);
            newType = type;
        }

        @Override
        public void updateDrawState(TextPaint paint) {
            apply(paint, newType);
        }

        @Override
        public void updateMeasureState(TextPaint paint) {
            apply(paint, newType);
        }

        private static void apply(Paint paint, Typeface tf) {
            int oldStyle;
            Typeface old = paint.getTypeface();
            if (old == null) {
                oldStyle = 0;
            } else {
                oldStyle = old.getStyle();
            }

            int fake = oldStyle & ~tf.getStyle();
            if ((fake & Typeface.BOLD) != 0) {
                paint.setFakeBoldText(true);
            }

            if ((fake & Typeface.ITALIC) != 0) {
                paint.setTextSkewX(-0.25f);
            }

            paint.setTypeface(tf);
        }
    }
}
